<template>
  <view class="chat-page">
    <!-- 聊天头部 -->
    <view class="chat-header">
      <view class="header-left">
        <text class="back-btn" @click="handleBack">← 返回</text>
      </view>
      <view class="header-center">
        <text class="header-title">{{ chatTitle }}</text>
        <text class="header-subtitle">{{ isOnline ? '在线' : '离线' }}</text>
      </view>
      <view class="header-right">
        <text v-if="currentSession?.status === 'ACTIVE'" class="close-btn" @click="handleCloseSession">
          结束
        </text>
      </view>
    </view>

    <!-- 消息列表 -->
    <scroll-view 
      class="message-list" 
      scroll-y 
      :scroll-top="scrollTop"
      :scroll-with-animation="true"
      @scrolltoupper="loadMoreMessages"
    >
      <view v-for="message in messages" :key="message.id" :class="['message-item', message.senderType === 'MEMBER' ? 'message-right' : 'message-left']">
        <image v-if="message.senderType === 'STAFF'" :src="message.senderAvatar || '/static/default-avatar.png'" class="avatar" />
        
        <view class="message-content-wrapper">
          <view v-if="message.senderType === 'STAFF'" class="message-sender">
            {{ message.senderName }}
          </view>
          
          <view v-if="!message.isRecalled" :class="['message-content', message.senderType === 'MEMBER' ? 'message-my' : 'message-other']">
            <!-- 文本消息 -->
            <text v-if="message.messageType === 'TEXT'">{{ message.content }}</text>
            
            <!-- 图片消息 -->
            <image 
              v-else-if="message.messageType === 'IMAGE'" 
              :src="message.fileUrl" 
              mode="aspectFit"
              class="message-image"
              @click="previewImage(message.fileUrl)"
            />
            
            <!-- 文件消息 -->
            <view v-else-if="message.messageType === 'FILE'" class="message-file">
              <text class="file-icon">📄</text>
              <view class="file-info">
                <text class="file-name">{{ message.fileName }}</text>
                <text class="file-size">{{ formatFileSize(message.fileSize) }}</text>
              </view>
            </view>
            
            <!-- 系统消息 -->
            <text v-else-if="message.messageType === 'SYSTEM'" class="system-message">
              {{ message.content }}
            </text>
          </view>
          
          <text v-else class="message-recalled">该消息已被撤回</text>
          
          <view class="message-time">{{ formatTime(message.createdAt) }}</view>
        </view>
        
        <image v-if="message.senderType === 'MEMBER'" :src="message.senderAvatar || '/static/default-avatar.png'" class="avatar" />
      </view>
      
      <!-- 空状态 -->
      <view v-if="messages.length === 0" class="empty-state">
        <text>暂无消息</text>
      </view>
    </scroll-view>

    <!-- 输入区域 -->
    <view class="input-area">
      <view class="input-toolbar">
        <text class="toolbar-btn" @click="selectImage">📷</text>
      </view>
      <view class="input-wrapper">
        <textarea 
          v-model="inputMessage" 
          class="message-input" 
          placeholder="输入消息..."
          :maxlength="500"
          :auto-height="true"
          @confirm="sendMessage"
        />
        <button class="send-btn" @click="sendMessage">发送</button>
      </view>
    </view>

    <!-- 评分对话框 -->
    <uni-popup ref="ratingPopup" type="dialog">
      <view class="rating-dialog">
        <text class="rating-title">为本次服务评分</text>
        <view class="rating-stars">
          <text 
            v-for="i in 5" 
            :key="i"
            class="star"
            :class="{ active: i <= rating }"
            @click="rating = i"
          >
            ⭐
          </text>
        </view>
        <textarea 
          v-model="ratingComment" 
          class="rating-comment" 
          placeholder="请输入评价（可选）"
          :maxlength="200"
        />
        <view class="rating-actions">
          <button class="rating-btn cancel-btn" @click="cancelRating">取消</button>
          <button class="rating-btn submit-btn" @click="submitRating">提交</button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'

// 状态
const sessionId = ref(null)
const currentSession = ref(null)
const messages = ref([])
const inputMessage = ref('')
const scrollTop = ref(0)
const isOnline = ref(false)
const rating = ref(5)
const ratingComment = ref('')
const ratingPopup = ref(null)
const ws = ref(null)

// 计算属性
const chatTitle = computed(() => {
  return currentSession.value?.type === 'CUSTOMER_SERVICE' ? '客服咨询' : '教练咨询'
})

// 生命周期
onLoad((options) => {
  if (options.sessionId) {
    sessionId.value = Number(options.sessionId)
    loadSession()
    loadMessages()
    connectWebSocket()
  } else {
    // 创建新会话
    createSession()
  }
})

onUnmounted(() => {
  disconnectWebSocket()
})

// 创建会话
async function createSession() {
  try {
    const token = uni.getStorageSync('token')
    const res = await uni.request({
      url: 'http://localhost:8080/api/v1/chat/sessions',
      method: 'POST',
      header: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      data: {
        type: 'CUSTOMER_SERVICE',
        title: '客服咨询'
      }
    })
    
    if (res.statusCode === 200 && res.data.code === 200) {
      sessionId.value = res.data.data.id
      currentSession.value = res.data.data
      connectWebSocket()
    } else {
      uni.showToast({
        title: '创建会话失败',
        icon: 'none'
      })
    }
  } catch (error) {
    console.error('创建会话失败:', error)
    uni.showToast({
      title: '创建会话失败',
      icon: 'none'
    })
  }
}

// 加载会话信息
async function loadSession() {
  try {
    const token = uni.getStorageSync('token')
    const res = await uni.request({
      url: `http://localhost:8080/api/v1/chat/sessions/${sessionId.value}`,
      method: 'GET',
      header: {
        'Authorization': `Bearer ${token}`
      }
    })
    
    if (res.statusCode === 200 && res.data.code === 200) {
      currentSession.value = res.data.data
    }
  } catch (error) {
    console.error('加载会话失败:', error)
  }
}

// 加载消息列表
async function loadMessages() {
  try {
    const token = uni.getStorageSync('token')
    const res = await uni.request({
      url: 'http://localhost:8080/api/v1/chat/messages',
      method: 'GET',
      header: {
        'Authorization': `Bearer ${token}`
      },
      data: {
        sessionId: sessionId.value,
        page: 1,
        pageSize: 50
      }
    })
    
    if (res.statusCode === 200 && res.data.code === 200) {
      messages.value = res.data.data.list.reverse()
      scrollToBottom()
      
      // 标记消息为已读
      markMessagesAsRead()
    }
  } catch (error) {
    console.error('加载消息失败:', error)
  }
}

// 连接 WebSocket
function connectWebSocket() {
  const token = uni.getStorageSync('token')
  const wsUrl = `ws://localhost:8080/api/v1/chat/ws?token=${token}`
  
  ws.value = uni.connectSocket({
    url: wsUrl,
    success: () => {
      console.log('WebSocket连接成功')
    },
    fail: (error) => {
      console.error('WebSocket连接失败:', error)
    }
  })
  
  ws.value.onOpen(() => {
    console.log('WebSocket已打开')
    isOnline.value = true
    // 发送心跳
    startHeartbeat()
  })
  
  ws.value.onMessage((res) => {
    try {
      const message = JSON.parse(res.data)
      console.log('收到消息:', message)
      handleWebSocketMessage(message)
    } catch (error) {
      console.error('解析消息失败:', error)
    }
  })
  
  ws.value.onClose(() => {
    console.log('WebSocket已关闭')
    isOnline.value = false
    stopHeartbeat()
  })
  
  ws.value.onError((error) => {
    console.error('WebSocket错误:', error)
    isOnline.value = false
  })
}

// 断开 WebSocket
function disconnectWebSocket() {
  if (ws.value) {
    ws.value.close()
    ws.value = null
  }
  stopHeartbeat()
}

// 处理 WebSocket 消息
function handleWebSocketMessage(message) {
  switch (message.type) {
    case 'NEW_MESSAGE':
      if (message.data.sessionId === sessionId.value) {
        messages.value.push(message.data)
        scrollToBottom()
        markMessagesAsRead()
      }
      break
    case 'MESSAGE_READ':
      const { messageIds } = message.data
      messages.value.forEach(msg => {
        if (messageIds.includes(msg.id)) {
          msg.isRead = true
        }
      })
      break
    case 'SESSION_UPDATE':
      loadSession()
      break
    case 'PONG':
      console.log('收到心跳响应')
      break
  }
}

// 心跳定时器
let heartbeatTimer = null

function startHeartbeat() {
  heartbeatTimer = setInterval(() => {
    if (ws.value) {
      ws.value.send({
        data: JSON.stringify({
          type: 'PING',
          data: {},
          timestamp: new Date().toISOString()
        })
      })
    }
  }, 30000) // 30秒
}

function stopHeartbeat() {
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer)
    heartbeatTimer = null
  }
}

// 发送消息
async function sendMessage() {
  if (!inputMessage.value.trim()) return
  if (!sessionId.value) {
    uni.showToast({
      title: '会话未就绪',
      icon: 'none'
    })
    return
  }

  try {
    const token = uni.getStorageSync('token')
    const res = await uni.request({
      url: 'http://localhost:8080/api/v1/chat/messages',
      method: 'POST',
      header: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      data: {
        sessionId: sessionId.value,
        messageType: 'TEXT',
        content: inputMessage.value.trim()
      }
    })
    
    if (res.statusCode === 200 && res.data.code === 200) {
      inputMessage.value = ''
    } else {
      uni.showToast({
        title: '发送失败',
        icon: 'none'
      })
    }
  } catch (error) {
    console.error('发送消息失败:', error)
    uni.showToast({
      title: '发送失败',
      icon: 'none'
    })
  }
}

// 选择图片
function selectImage() {
  uni.chooseImage({
    count: 1,
    success: (res) => {
      uploadImage(res.tempFilePaths[0])
    }
  })
}

// 上传图片
async function uploadImage(filePath) {
  try {
    const token = uni.getStorageSync('token')
    uni.showLoading({ title: '上传中...' })
    
    const res = await uni.uploadFile({
      url: 'http://localhost:8080/api/v1/chat/upload',
      filePath: filePath,
      name: 'file',
      formData: {
        sessionId: sessionId.value
      },
      header: {
        'Authorization': `Bearer ${token}`
      }
    })
    
    uni.hideLoading()
    
    if (res.statusCode === 200) {
      const data = JSON.parse(res.data)
      if (data.code === 200) {
        uni.showToast({
          title: '发送成功',
          icon: 'success'
        })
      }
    } else {
      uni.showToast({
        title: '上传失败',
        icon: 'none'
      })
    }
  } catch (error) {
    uni.hideLoading()
    console.error('上传图片失败:', error)
    uni.showToast({
      title: '上传失败',
      icon: 'none'
    })
  }
}

// 预览图片
function previewImage(url) {
  uni.previewImage({
    urls: [url],
    current: url
  })
}

// 标记消息已读
async function markMessagesAsRead() {
  try {
    const unreadIds = messages.value
      .filter(m => !m.isRead && m.senderType === 'STAFF')
      .map(m => m.id)
    
    if (unreadIds.length === 0) return
    
    const token = uni.getStorageSync('token')
    await uni.request({
      url: 'http://localhost:8080/api/v1/chat/messages/read',
      method: 'POST',
      header: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      data: {
        messageIds: unreadIds
      }
    })
  } catch (error) {
    console.error('标记已读失败:', error)
  }
}

// 关闭会话
function handleCloseSession() {
  ratingPopup.value.open()
}

// 提交评分
async function submitRating() {
  try {
    const token = uni.getStorageSync('token')
    const res = await uni.request({
      url: `http://localhost:8080/api/v1/chat/sessions/${sessionId.value}/close`,
      method: 'POST',
      header: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      data: {
        rating: rating.value,
        ratingComment: ratingComment.value
      }
    })
    
    if (res.statusCode === 200 && res.data.code === 200) {
      ratingPopup.value.close()
      uni.showToast({
        title: '感谢您的评价',
        icon: 'success'
      })
      setTimeout(() => {
        uni.navigateBack()
      }, 1500)
    }
  } catch (error) {
    console.error('提交评分失败:', error)
    uni.showToast({
      title: '提交失败',
      icon: 'none'
    })
  }
}

// 取消评分
function cancelRating() {
  ratingPopup.value.close()
}

// 加载更多消息
function loadMoreMessages() {
  // TODO: 实现加载历史消息
}

// 滚动到底部
function scrollToBottom() {
  setTimeout(() => {
    scrollTop.value = 999999
  }, 100)
}

// 返回
function handleBack() {
  uni.navigateBack()
}

// 格式化时间
function formatTime(time) {
  const date = new Date(time)
  return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
}

// 格式化文件大小
function formatFileSize(bytes) {
  if (!bytes) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i]
}
</script>

<style scoped lang="scss">
.chat-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f5f5f5;
}

.chat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20rpx 30rpx;
  background-color: #fff;
  border-bottom: 1rpx solid #e5e5e5;

  .header-left, .header-right {
    width: 120rpx;
  }

  .back-btn, .close-btn {
    font-size: 28rpx;
    color: #4B0082;
  }

  .header-center {
    flex: 1;
    text-align: center;

    .header-title {
      display: block;
      font-size: 32rpx;
      font-weight: 500;
      color: #333;
    }

    .header-subtitle {
      display: block;
      font-size: 24rpx;
      color: #999;
      margin-top: 8rpx;
    }
  }
}

.message-list {
  flex: 1;
  padding: 20rpx;
  overflow-y: auto;

  .message-item {
    display: flex;
    margin-bottom: 30rpx;

    .avatar {
      width: 80rpx;
      height: 80rpx;
      border-radius: 50%;
      margin: 0 20rpx;
    }

    .message-content-wrapper {
      max-width: 500rpx;

      .message-sender {
        font-size: 24rpx;
        color: #999;
        margin-bottom: 8rpx;
      }

      .message-content {
        padding: 20rpx;
        border-radius: 12rpx;
        word-break: break-all;

        &.message-other {
          background-color: #fff;
          color: #333;
        }

        &.message-my {
          background-color: #4B0082;
          color: #fff;
        }

        .message-image {
          max-width: 400rpx;
          max-height: 300rpx;
          border-radius: 8rpx;
        }

        .message-file {
          display: flex;
          align-items: center;

          .file-icon {
            font-size: 48rpx;
            margin-right: 16rpx;
          }

          .file-info {
            .file-name {
              display: block;
              font-size: 28rpx;
            }

            .file-size {
              display: block;
              font-size: 24rpx;
              color: #999;
              margin-top: 4rpx;
            }
          }
        }

        .system-message {
          font-size: 24rpx;
          color: #999;
          font-style: italic;
        }
      }

      .message-recalled {
        font-size: 24rpx;
        color: #999;
        font-style: italic;
      }

      .message-time {
        font-size: 20rpx;
        color: #999;
        margin-top: 8rpx;
      }
    }

    &.message-right {
      flex-direction: row-reverse;

      .message-content-wrapper {
        align-items: flex-end;
        text-align: right;
      }
    }
  }

  .empty-state {
    text-align: center;
    padding: 100rpx 0;
    color: #999;
    font-size: 28rpx;
  }
}

.input-area {
  background-color: #fff;
  border-top: 1rpx solid #e5e5e5;
  padding: 20rpx;

  .input-toolbar {
    display: flex;
    padding-bottom: 16rpx;

    .toolbar-btn {
      font-size: 48rpx;
      margin-right: 20rpx;
    }
  }

  .input-wrapper {
    display: flex;
    align-items: flex-end;

    .message-input {
      flex: 1;
      min-height: 80rpx;
      max-height: 200rpx;
      padding: 16rpx;
      background-color: #f5f5f5;
      border-radius: 8rpx;
      font-size: 28rpx;
    }

    .send-btn {
      margin-left: 16rpx;
      padding: 16rpx 32rpx;
      background-color: #4B0082;
      color: #fff;
      border-radius: 8rpx;
      font-size: 28rpx;
      border: none;
    }
  }
}

.rating-dialog {
  padding: 40rpx;
  background-color: #fff;
  border-radius: 16rpx;

  .rating-title {
    display: block;
    text-align: center;
    font-size: 32rpx;
    font-weight: 500;
    margin-bottom: 32rpx;
  }

  .rating-stars {
    display: flex;
    justify-content: center;
    margin-bottom: 32rpx;

    .star {
      font-size: 60rpx;
      margin: 0 8rpx;
      opacity: 0.3;

      &.active {
        opacity: 1;
      }
    }
  }

  .rating-comment {
    width: 100%;
    min-height: 120rpx;
    padding: 16rpx;
    border: 1rpx solid #e5e5e5;
    border-radius: 8rpx;
    font-size: 28rpx;
    margin-bottom: 32rpx;
  }

  .rating-actions {
    display: flex;
    justify-content: space-between;

    .rating-btn {
      flex: 1;
      padding: 20rpx;
      border-radius: 8rpx;
      font-size: 28rpx;
      border: none;

      &.cancel-btn {
        background-color: #f5f5f5;
        color: #666;
        margin-right: 16rpx;
      }

      &.submit-btn {
        background-color: #4B0082;
        color: #fff;
      }
    }
  }
}
</style>

